/**
 * 复数变化规则
 *
 *
 */
export class PluralizeRule {
	/**
	 * 不规则
	 *
	 * @protected
	 * @type {string[]}
	 * @memberof PluralizeRule
	 */
	protected irregular: Map<string, string> = new Map();

	/**
	 * 不可数
	 *
	 * @protected
	 * @type {string[]}
	 * @memberof PluralizeRule
	 */
	protected uncountable: string[] = [
		'equipment',
		'information',
		'rice',
		'money',
		'species',
		'series',
		'fish',
		'sheep',
		'people',
		'men',
		'children',
		'sexes',
		'moves',
		'stadiums',
		'oxen',
		'octopi',
		'viri',
		'aliases',
		'quizzes',
	];

	/**
	 * 初始化pluralizeRule对象
	 *
	 * @param opts 额外参数
	 * @memberof PluralizeRule
	 */
	public constructor(opts: any = {}) {
		this.initIrregular();
	}

	/**
	 * 初始化不规则变化
	 *
	 * @param opts 额外参数
	 * @memberof PluralizeRule
	 */
	protected initIrregular() {
		this.irregular.set('person', 'people');
		this.irregular.set('man', 'men');
		this.irregular.set('child', 'children');
		this.irregular.set('sex', 'sexes');
		this.irregular.set('move', 'moves');
		this.irregular.set('stadium', 'stadiums');
	}

	/**
	 * 是否为不可数
	 *
	 * @param word 单词
	 * @returns 返回判断
	 * @memberof PluralizeRule
	 */
	public isUncountable(word: string) {
		const index: number = this.uncountable.findIndex((wordStr: string) => {
			return Object.is(word, wordStr);
		});
		if (index == -1) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 不规则变化
	 *
	 * @param word 单词
	 * @returns 返回变化值
	 * @memberof PluralizeRule
	 */
	public irregularChange(word: string) {
		for (let item of this.irregular.entries()) {
			if (word && word.endsWith(item[0])) {
				return word.replace(new RegExp(item[0], 'g'), item[1]);
			}
		}
		return this.irregular.get(word);
	}

	/**
	 * 规则变化
	 *
	 * @param word 单词
	 * @returns 返回变化值
	 * @memberof PluralizeRule
	 */
	public ruleChange(word: string) {
		if (/(ax|test)is$/.test(word)) return word.replace(/is$/, 'es');
		if (/(octop|vir)us$/.test(word)) return word.replace(/us$/, 'i');
		if (/(octop|vir)i$/.test(word)) return word;
		if (/(alias|status)$/.test(word)) return word + 'es';
		if (/(bu)s$/.test(word)) return word.replace(/s$/, 'ses');
		if (/(buffal|tomat)o$/.test(word)) return word.replace(/o$/, 'oes');
		if (/([ti])um$/.test(word)) return word.replace(/um$/, 'a');
		if (/([ti])a$/.test(word)) return word;
		if (/sis$/.test(word)) return word.replace(/sis$/, 'ses');
		if (/(?:([^f])fe|([lr])f)$/.test(word))
			return word.substring(0, word.length - 1) + 'ves';
		if (/(hive)$/.test(word)) return word + 's';
		if (/([^aeiouy]|qu)y$/.test(word)) return word.replace(/y$/, 'ies');
		if (/(x|ch|ss|sh)$/.test(word)) return word + 'es';
		if (/(matr|vert|ind)ix|ex$/.test(word))
			return word.replace(/ix|ex$/, 'ices');
		if (/([m|l])ouse$/.test(word)) return word.replace(/ouse$/, 'ice');
		if (/([m|l])ice$/.test(word)) return word;
		if (/^(ox)$$/.test(word)) return word + 'en';
		if (/(quiz)$/.test(word)) return word + 'zes';
		if (/s$/.test(word)) return word.replace(/s$/, 's');
		return word + 's';
	}
}
